/*
 * Service.java
 * 
 * This file is part of Netuno.
 * 
 * CajuScript is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3, or (at your option) 
 * any later version.
 * 
 * CajuScript is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with CajuScript.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.netuno;

import java.net.Socket;
import org.apache.log4j.Logger;
import org.netuno.psamata.script.ScriptRunner;

/**
 * Service, receive client and start communication between client and server.
 * @author eduveks
 */
public class Service extends Thread {
    /**
     * Logger.
     */
    private static Logger logger = Logger.getLogger(Service.class);
    /**
     * Sleep.
     */
    private boolean sleep = true;
    /**
     * Sleep Lock.
     */
    private final Object sleepLock = new Object();
    /**
     * Client Socket.
     */
    private Socket clientSocket;
    /**
     * Thread ID.
     */
    private int threadID = -1;
    /**
     * Execution timer.
     */
    private long time = 0;
    /**
     * Input Stream.
     */
    private org.netuno.psamata.io.InputStream in = null;
    /**
     * Output Stream.
     */
    private org.netuno.psamata.io.OutputStream out = null;
    /**
     * Service.
     * @param thread Thread ID
     */
    public Service(final int thread) {
        logger.info("New service thread started.");
        threadID = thread;
        start();
    }
    /**
     * Set Client.
     * @param client Client Socket
     */
    public final void setClient(final Socket client) {
        clientSocket = client;
    }
    /**
     * Get Time.
     * @return Time
     */
    public final long getTime() {
        return time;
    }
    /**
     * Run service.
     */
    @Override
    public final void run() {
        synchronized (sleepLock) {
            while (true) {
                if (sleep) {
                    try {
                        sleepLock.wait();
                    } catch (Exception e) {
                        logger.error("Sleeping.", e);
                    }
                } else {
                    sleep = false;
                    ScriptRunner scriptRunner = null;
                    try {
                        if (Config.isStarting()) {
                            ServiceMonitor.setAllowNewConnections(false);
                        }
                        time = System.currentTimeMillis();
                        ServiceData serviceData = new ServiceData(
                        clientSocket, threadID
                        );
                        in = serviceData.getInputStream();
                        out = serviceData.getOutputStream();
                        String path = ScriptRunner.searchFile("netuno_service");
                        scriptRunner = new ScriptRunner();
                        scriptRunner.getBindings().put("netuno_service_data", serviceData);
                        scriptRunner.runFile(path);
                    } catch (Exception e) {
                        logger.warn("Client.", e);
                    } finally {
                        if (scriptRunner != null) {
                            scriptRunner.clear();
                        }
                        scriptRunner = null;
                        finish();
                        if (Config.isStarting()) {
                            Config.setStarting(false);
                            ServiceMonitor.setAllowNewConnections(true);
                        }
                    }
                    sleep = true;
                }
            }
        }
    }
    /**
     * Start.
     */
    public final void go() {
        synchronized (sleepLock) {
            sleep = false;
            sleepLock.notify();
        }
    }
    /**
     * Finish.
     */
    public final void finish() {
        try {
            try {
                in.close();
            } catch (Exception e) {
                logger.warn("Client input close.", e);
            }
            try {
                out.close();
            } catch (Exception e) {
                logger.warn("Client output close.", e);
            }
            try {
                clientSocket.close();
            } catch (Exception e) {
                logger.warn("Client socket close.", e);
            }
            logger.info("End connection.");
        } catch (Exception e) {
            logger.warn("Client close.", e);
        } finally {
            in = null;
            out = null;
            clientSocket = null;
            time = 0;
            org.netuno.psamata.Memory.collectGarbage();
        }
    }
    /**
     * Sleeping.
     * @return Sleeping
     */
    public final boolean sleeping() {
        return sleep;
    }
}
